home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevatx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  9.2 KB  |  275 lines

  1. /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
  2.  
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 U.S.A.
  16.  
  17.    This program may also be distributed as part of AFPL Ghostscript,
  18.    under the terms of the Aladdin Free Public License (the "License").
  19.  
  20.    AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  21.    or distributor accepts any responsibility for the consequences of using
  22.    it, or for whether it serves any particular purpose or works at all,
  23.    unless he or she says so in writing.  Refer to the Aladdin Free Public
  24.    License (the "License") for full details.
  25.  
  26.    Every copy of AFPL Ghostscript must include a copy of the License,
  27.    normally in a plain ASCII text file named PUBLIC.  The License grants you
  28.    the right to copy, modify and redistribute AFPL Ghostscript, but only
  29.    under certain conditions described in the License.  Among other things, the
  30.    License requires that the copyright notice and this notice be preserved on
  31.    all copies.
  32. */
  33.  
  34. /*$Id: gdevatx.c,v 1.6 2000/09/19 19:00:11 lpd Exp $ */
  35. /* Practical Automation ATX-23, -24, and -38 driver */
  36. #include "math_.h"
  37. #include "gdevprn.h"
  38.  
  39. /*
  40.  * All of the ATX printers have an unprintable margin of 0.125" at the top
  41.  * and bottom of the page.  They also have unprintable left/right margins:
  42.  *    ATX-23    0.25"
  43.  *    ATX-24    0.193"
  44.  *    ATS-38    0.25"
  45.  * The code below assumes that coordinates refer only to the *printable*
  46.  * part of each page.  This is wrong and must eventually be changed.
  47.  */
  48.  
  49. /* Define the printer commands. */
  50. #define ATX_SET_PAGE_LENGTH "\033f"  /* + 2-byte length */
  51. #define ATX_VERTICAL_TAB "\033L"  /* + 2-byte count */
  52. #define ATX_UNCOMPRESSED_DATA "\033d"  /* + 2-byte count */
  53. #define ATX_COMPRESSED_DATA "\033x"  /* + 1-byte word count */
  54. #define ATX_END_PAGE "\033e"
  55.  
  56. /* The device descriptors */
  57. private dev_proc_print_page(atx23_print_page);
  58. private dev_proc_print_page(atx24_print_page);
  59. private dev_proc_print_page(atx38_print_page);
  60.  
  61. #define ATX_DEVICE(dname, w10, h10, dpi, lrm, btm, print_page)\
  62.   prn_device_margins(prn_std_procs, dname, w10, h10, dpi, dpi, 0, 0,\
  63.              lrm, btm, lrm, btm, 1, print_page)
  64.  
  65. const gx_device_printer gs_atx23_device = /* real width = 576 pixels */
  66. ATX_DEVICE("atx23", 28 /* 2.84" */, 35 /* (minimum) */,
  67.        203, 0.25, 0.125, atx23_print_page);
  68.  
  69. const gx_device_printer gs_atx24_device = /* real width = 832 pixels */
  70. ATX_DEVICE("atx24", 41 /* 4.1" */, 35 /* (minimum) */,
  71.        203, 0.193, 0.125, atx24_print_page);
  72.  
  73. const gx_device_printer gs_atx38_device = /* real width = 2400 pixels */
  74. ATX_DEVICE("atx38", 80 /* 8.0" */, 35 /* (minimum) */,
  75.        300, 0.25, 0.125, atx38_print_page);
  76.  
  77. /* Output a printer command with a 2-byte, little-endian numeric argument. */
  78. private void
  79. fput_atx_command(FILE *f, const char *str, int value)
  80. {
  81.     fputs(str, f);
  82.     fputc((byte)value, f);
  83.     fputc((byte)(value >> 8), f);
  84. }
  85.  
  86. /*
  87.  * Attempt to compress a scan line of data.  in_size and out_size are even.
  88.  * Return -1 if the compressed data would exceed out_size, otherwise the
  89.  * size of the compressed data (always even).
  90.  */
  91. #define MIN_IN_SIZE_TO_COMPRESS 50
  92. #define MAX_COMPRESSED_SEGMENT_PAIRS 127
  93. #define MAX_UNCOMPRESSED_SEGMENT_PAIRS 255
  94. #define COMPRESSED_SEGMENT_COMMAND 0x80    /* + # of repeated pairs */
  95. #define UNCOMPRESSED_SEGMENT_COMMAND 0x7f /* followed by # of pairs */
  96. private int
  97. atx_compress(const byte *in_buf, int in_size, byte *out_buf, int out_size)
  98. {
  99.     const byte *const in_end = in_buf + in_size;
  100.     byte *const out_end = out_buf + out_size;
  101.     const byte *in = in_buf;
  102.     byte *out = out_buf;
  103.     byte *out_command;
  104.     int pair_count;
  105.  
  106.     if (in_size < MIN_IN_SIZE_TO_COMPRESS)
  107.     return -1;            /* not worth compressing */
  108.  
  109.     /* Start a new segment. */
  110.  New_Segment:
  111.     if (in == in_end)        /* end of input data */
  112.     return out - out_buf;
  113.     if (out == out_end)        /* output buffer full */
  114.     return -1;
  115.     out_command = out;
  116.     out += 2;
  117.     if (in[1] == in[0]) {        /* start compressed segment */
  118.     /* out[-2] will be compressed segment command */
  119.     out[-1] = in[0];
  120.     pair_count = 1;
  121.     goto Scan_Compressed_Pair;
  122.     } else {            /* start uncompressed segment */
  123.     out[-2] = UNCOMPRESSED_SEGMENT_COMMAND;
  124.     /* out[-1] will be pair count */
  125.     pair_count = 0;
  126.     goto Scan_Uncompressed_Pair;
  127.     }
  128.  
  129.     /* Scan compressed data. */
  130.  Scan_Compressed:
  131.     if (pair_count == MAX_COMPRESSED_SEGMENT_PAIRS ||
  132.     in == in_end || in[0] != in[-1] || in[1] != in[0]
  133.     ) {            /* end the segment */
  134.     out_command[0] = COMPRESSED_SEGMENT_COMMAND + pair_count;
  135.     goto New_Segment;
  136.     }
  137.     ++pair_count;
  138.  Scan_Compressed_Pair:
  139.     in += 2;
  140.     goto Scan_Compressed;
  141.  
  142.     /* Scan uncompressed data. */
  143.  Scan_Uncompressed:
  144.     if (pair_count == MAX_UNCOMPRESSED_SEGMENT_PAIRS ||
  145.     in == in_end || in[1] == in[0]
  146.     ) {            /* end the segment */
  147.     out_command[1] = pair_count;
  148.     goto New_Segment;
  149.     }
  150.  Scan_Uncompressed_Pair:
  151.     if (out == out_end)        /* output buffer full */
  152.     return -1;
  153.     out[0] = in[0], out[1] = in[1];
  154.     in += 2;
  155.     out += 2;
  156.     ++pair_count;
  157.     goto Scan_Uncompressed;
  158.   
  159. }
  160.  
  161. /* Send the page to the printer. */
  162. private int
  163. atx_print_page(gx_device_printer *pdev, FILE *f, int max_width_bytes)
  164. {
  165.     /*
  166.      * The page length command uses 16 bits to represent the length in
  167.      * units of 0.01", so the maximum representable page length is 
  168.      * 655.35", including the unprintable top and bottom margins.
  169.      * Compute the maximum height of the printable area in pixels.
  170.      */
  171.     float top_bottom_skip = (pdev->HWMargins[1] + pdev->HWMargins[3]) / 72.0;
  172.     int max_height = (int)(pdev->HWResolution[1] * 655 - top_bottom_skip);
  173.     int height = min(pdev->height, max_height);
  174.     int page_length_100ths =
  175.     (int)ceil((height / pdev->HWResolution[1] + top_bottom_skip) * 100);
  176.     gs_memory_t *mem = pdev->memory;
  177.     int raster = gx_device_raster((gx_device *)pdev, true);
  178.     byte *buf;
  179.     /*
  180.      * ATX_COMPRESSED_DATA only takes a 1-byte (word) count.
  181.      * Thus no compressed scan line can take more than 510 bytes.
  182.      */
  183.     int compressed_raster = min(raster / 2, 510); /* require 50% compression */
  184.     byte *compressed;
  185.     int blank_lines, lnum;
  186.     int code = 0;
  187.  
  188.     /* Enforce a minimum 3" page length. */
  189.     if (page_length_100ths < 300)
  190.     page_length_100ths = 300;
  191.     buf = gs_alloc_bytes(mem, raster, "atx_print_page(buf)");
  192.     compressed = gs_alloc_bytes(mem, compressed_raster,
  193.                 "atx_print_page(compressed)");
  194.     if (buf == 0 || compressed == 0) {
  195.     code = gs_note_error(gs_error_VMerror);
  196.     goto done;
  197.     }
  198.     fput_atx_command(f, ATX_SET_PAGE_LENGTH, page_length_100ths);
  199.     for (blank_lines = 0, lnum = 0; lnum < height; ++lnum) {
  200.     byte *row;
  201.     byte *end;
  202.     int count;
  203.  
  204.     gdev_prn_get_bits(pdev, lnum, buf, &row);
  205.     /* Find the end of the non-blank data. */
  206.     for (end = row + raster; end > row && end[-1] == 0 && end[-2] == 0; )
  207.         end -= 2;
  208.     if (end == row) {        /* blank line */
  209.         ++blank_lines;
  210.         continue;
  211.     }
  212.     if (blank_lines) {        /* skip vertically */
  213.         fput_atx_command(f, ATX_VERTICAL_TAB, blank_lines + 1);
  214.         blank_lines = 0;
  215.     }
  216.     /* Truncate the line to the maximum printable width. */
  217.     if (end - row > max_width_bytes)
  218.         end = row + max_width_bytes;
  219.     count = atx_compress(row, end - row, compressed, compressed_raster);
  220.     if (count >= 0) {        /* compressed line */
  221.         /*
  222.          * Note that since compressed_raster can't exceed 510, count
  223.          * can't exceed 510 either.
  224.          */
  225.         fputs(ATX_COMPRESSED_DATA, f);
  226.         fputc(count / 2, f);
  227.         fwrite(compressed, 1, count, f);
  228.     } else {            /* uncompressed line */
  229.         int num_bytes = end - row;
  230.  
  231.         fput_atx_command(f, ATX_UNCOMPRESSED_DATA, num_bytes);
  232.         fwrite(row, 1, num_bytes, f);
  233.     }
  234.     }
  235.  
  236. #if 0    /**************** MAY NOT BE NEEDED ****************/
  237.     /* Enforce the minimum page length, and skip any final blank lines. */
  238.     {
  239.     int paper_length = (int)(pdev->HWResolution[1] * 3 + 0.5);
  240.     int printed_length = height - blank_lines;
  241.  
  242.     if (height > paper_length)
  243.         paper_length = height;
  244.     if (printed_length < paper_length)
  245.         fput_atx_command(f, ATX_VERTICAL_TAB,
  246.                  paper_length - printed_length + 1);
  247.     }
  248. #endif
  249.  
  250.     /* End the page. */
  251.     fputs(ATX_END_PAGE, f);
  252.  
  253.  done:
  254.     gs_free_object(mem, compressed, "atx_print_page(compressed)");
  255.     gs_free_object(mem, buf, "atx_print_page(buf)");
  256.     return code;
  257. }
  258.  
  259. /* Print pages with specified maximum pixel widths. */
  260. private int
  261. atx23_print_page(gx_device_printer *pdev, FILE *f)
  262. {
  263.     return atx_print_page(pdev, f, 576 / 8);
  264. }
  265. private int
  266. atx24_print_page(gx_device_printer *pdev, FILE *f)
  267. {
  268.     return atx_print_page(pdev, f, 832 / 8);
  269. }
  270. private int
  271. atx38_print_page(gx_device_printer *pdev, FILE *f)
  272. {
  273.     return atx_print_page(pdev, f, 2400 / 8);
  274. }
  275.